package com.chungkui.ratelimiter.aspect;

import com.chungkui.check.util.AspectUtil;
import com.chungkui.ratelimiter.RateLimiterService;
import com.chungkui.ratelimiter.anotation.RateLimiter;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import java.lang.reflect.Method;

/**
 * Copyright (C), 2002-2019,草帽团开发团队
 * 〈注解式校验切面类〉<br>
 * 〈功能详细描述〉
 *
 * @author jason
 * @fileName: CheckAspect.java
 * @date: 2019/6/28 12:54
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
@Aspect
public class RateLimiterAspect {
    private final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
    private LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
    private ExpressionParser parser = new SpelExpressionParser();

    public RateLimiterAspect() {
        log.info("chungkui rateLimiter,init success");
    }

    @Autowired
    RateLimiterService rateLimiterService;

    @Pointcut("@annotation(com.chungkui.ratelimiter.anotation.RateLimiter)")
    public void checkPointcut() {
        throw new UnsupportedOperationException();
    }

    @Around("checkPointcut()")
    public Object checkAround(ProceedingJoinPoint joinPoint) throws Throwable {
        /*获取注解*/
        RateLimiter rateLimiter = getAnnotation(joinPoint);
        String key = getMethodKey(joinPoint);
        if (rateLimiter != null) {
            if (StringUtils.isNotEmpty(rateLimiter.dynamicParam())) {
                Signature signature = joinPoint.getSignature();
                MethodSignature methodSignature = (MethodSignature) signature;
                Method method = methodSignature.getMethod();
                /*取参数模式*/
                Expression expression = parser.parseExpression(rateLimiter.dynamicParam());
                String dyParam = expression.getValue(bindParam(method, joinPoint.getArgs()), String.class);
                rateLimiterService.limit(rateLimiter, key, dyParam);
            } else {
                rateLimiterService.limit(rateLimiter, key);
            }
        }
        return joinPoint.proceed();
    }

    private EvaluationContext bindParam(Method method, Object[] args) {
        //获取方法的参数名
        String[] params = discoverer.getParameterNames(method);
        //将参数名与参数值对应起来
        EvaluationContext context = new StandardEvaluationContext();
        for (int len = 0; len < params.length; len++) {
            context.setVariable(params[len], args[len]);
        }
        return context;
    }

    /**
     * 获取方法中的注解信息
     */
    private RateLimiter getAnnotation(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        if (method != null) {
            return method.getAnnotation(RateLimiter.class);
        }
        return null;
    }

    /**
     * 获取方法中的注解信息
     */
    private String getMethodKey(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        return AspectUtil.getMethodKey(method);
    }
}
